#pragma once

#include "CssGrammar.hpp"




namespace Engine
{
	namespace Ui
	{
		/**
		* This is a sophisticated css parser. It parses code into an in-memory
		* representation of the given document.
		* In order to do that, it works in 3 stages. The first stage removes any comment(s)
		* from the code, the second stage parses the code and creates the representation, while
		* the third stage looks for semantic errors, like a referencing a class that is not
		* defined within the document and creates the a useful representation of the css document,
		* ie. all attributes are now boost::any types, created by a factory.
		*/
		class CssParser
		{
		public:

			typedef CssClass::attribute_functor   attribute_functor;
			typedef CssClass::attribute_factory   attribute_factory;

			typedef CssClass::Errors              Errors;

		private:

			QRegExp             m_mlCommentRx;
			QRegExp             m_commentRx;
			CssGrammar          m_grammar;

			std::stringstream   m_errorStream;
			std::size_t         m_line;
			std::size_t         m_col;

			attribute_factory   m_factory;

		public:

			CssParser();



			/**
			* Register the given functor for that attribute with the factory.
			*/
			void registerAttribute(Attributes::Type attr, const attribute_functor& functor);



			/**
			* Parse the given code into a css_document structure.
			*/
			bool parse(QString code, CssDocument& doc, std::vector<Error>& errors);

		private:

			/**
			* Parse the given code into a css_document structure.
			*/
			void parse(const std::string& code, QList<CssParseClass>& classes, std::vector<Error>& errors);

			/**
			* Expand a css document by merging all parsed css classes into it.
			* A document uses a different structure and cannot be parsed directly.
			* Also, all attributes are fabricated here.
			*/
			void expand(const QList<CssParseClass>& classes, CssDocument& doc, std::vector<Error>& errors);

			/**
			* Get the exact line and column where parsing failed.
			*/
			std::string where() const;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
